---
id: message-passing
title: Workflow message passing - Java SDK
sidebar_label: Messages
description: Develop with Queries, Signals, and Updates with the Temporal Java SDK.
toc_max_heading_level: 3
keywords:
  - temporal java signals
  - send signal from client
  - send signal from workflow
  - signal with start
  - workflow queries
  - sending queries
  - workflow updates
  - dynamic workflows
  - dynamic activities
  - dynamic signals
  - dynamic queries
tags:
  - Workflows
  - Messages
  - Signals
  - Queries
  - Updates
  - Java SDK
  - Temporal SDKs
---

A Workflow can act like a stateful web service that receives messages: Queries, Signals, and Updates.
The Workflow implementation defines these endpoints via handler methods that can react to incoming messages and return values.
Temporal Clients use messages to read Workflow state and control execution.
See [Workflow message passing](/encyclopedia/workflow-message-passing) for a general overview of this topic.
This page introduces these features for the Temporal Java SDK.

## Write message handlers {#writing-message-handlers}

Follow these guidelines when writing your message handlers:

- Message handlers are defined as methods on the Workflow class, using one of the three annotations: [`@QueryMethod`](https://www.javadoc.io/doc/io.temporal/temporal-sdk/latest/io/temporal/workflow/QueryMethod.html), [`@SignalMethod`](https://www.javadoc.io/doc/io.temporal/temporal-sdk/latest/io/temporal/workflow/SignalMethod.html), and [`@UpdateMethod`](https://www.javadoc.io/doc/io.temporal/temporal-sdk/latest/io/temporal/workflow/UpdateMethod.html).
- The parameters and return values of handlers and the main Workflow function must be [serializable](/dataconversion).
- Prefer a single class with multiple fields over using multiple input parameters.
  A class allows you to add fields without changing the calling signature.

### Query handlers {#queries}

A [Query](/encyclopedia/workflow-message-passing#sending-queries) is a synchronous operation that retrieves state from a Workflow Execution:

```java
public class MessagePassingIntro {

    public enum Language {
        CHINESE,
        ENGLISH,
        FRENCH,
        SPANISH,
        PORTUGUESE,
    }

    public static class GetLanguagesInput {
        public boolean includeUnsupported;

        public GetLanguagesInput() {
            this.includeUnsupported = false;
        }

        public GetLanguagesInput(boolean includeUnsupported) {
            this.includeUnsupported = includeUnsupported;
        }
    }

    @WorkflowInterface
    public interface GreetingWorkflow {
        ...
        // 👉 Use the @QueryMethod annotation to define a Query handler in the
        // Workflow interface.
        @QueryMethod
        List<Language> getLanguages(GetLanguagesInput input);
    }

    public static class GreetingWorkflowImpl implements GreetingWorkflow {
        ...
        @Override
        public List<Language> getLanguages(GetLanguagesInput input) {
            // 👉 The Query handler returns a value: it must not mutate the Workflow state
            // or perform blocking operations.
            if (input.includeUnsupported) {
                return Arrays.asList(Language.values());
            } else {
                return new ArrayList(greetings.keySet());
            }
        }
    }

}
```

- A Query handler must not modify Workflow state.
- You can't perform blocking operations such as executing an Activity in a Query handler.
- The Query annotation accepts an argument (`name`) as described in the API reference docs for [`@QueryMethod`](https://www.javadoc.io/doc/io.temporal/temporal-sdk/latest/io/temporal/workflow/QueryMethod.html).

### Signal handlers {#signals}

A [Signal](/encyclopedia/workflow-message-passing#sending-signals) is an asynchronous message sent to a running Workflow Execution to change its state and control its flow:

```java
public class MessagePassingIntro {

    public static class ApproveInput {
        private String name;

        public ApproveInput() {}

        public ApproveInput(String name) {
            this.name = name;
        }
    }

    @WorkflowInterface
    public interface GreetingWorkflow {
        ...
        // 👉 Use the @SignalMethod annotation to define a Signal handler in the
        // Workflow interface.
        @SignalMethod
        void approve(ApproveInput input);
    }

    public static class GreetingWorkflowImpl implements GreetingWorkflow {
        ...
        @Override
        public Language setLanguage(Language language) {
            // 👉 The Signal handler mutates the Workflow state but cannot return a value.
            Language previousLanguage = this.language;
            this.language = language;
            return previousLanguage;
        }
    }
}
```

- The handler should not return a value.
  The response is sent immediately from the server, without waiting for the Workflow to process the Signal.

- The Signal annotation accepts arguments (`name`, and `unfinished_policy`) as described in the API reference docs for [`@SignalMethod`](https://www.javadoc.io/doc/io.temporal/temporal-sdk/latest/io/temporal/workflow/SignalMethod.html).

- Signal (and Update) handlers can be blocking.
  This allows you to use Activities, Child Workflows, durable [`Workflow.sleep`](https://www.javadoc.io/doc/io.temporal/temporal-sdk/latest/io/temporal/workflow/Workflow.html#sleep(java.time.Duration)) Timers, [`Workflow.await`](https://www.javadoc.io/doc/io.temporal/temporal-sdk/latest/io/temporal/workflow/Workflow.html#await(java.time.Duration,java.util.function.Supplier)), and more.
  See [Blocking handlers](#blocking-handlers) and [Workflow message passing](/encyclopedia/workflow-message-passing) for guidelines on safely using blocking Signal and Update handlers.

### Update handlers and validators {#updates}

An [Update](/encyclopedia/workflow-message-passing#sending-updates) is a trackable synchronous request sent to a running Workflow Execution.
It can change the Workflow state, control its flow, and return a result.
The sender must wait until the Worker accepts or rejects the Update.
The sender may wait further to receive a returned value or an exception if something goes wrong:

```java
public class MessagePassingIntro {
    @WorkflowInterface
    public interface GreetingWorkflow {
        ...
        // 👉 Use the @UpdateMethod annotation to define an Update handler in the
        // Workflow interface.
        @UpdateMethod
        Language setLanguage(Language language);

        // 👉 Update validators are optional
        @UpdateValidatorMethod(updateName = "setLanguage")
        void setLanguageValidator(Language language);
    }

    public static class GreetingWorkflowImpl implements GreetingWorkflow {
        ...
        @Override
        public Language setLanguage(Language language) {
            // 👉 The Update handler can mutate the Workflow state and return a value.
            Language previousLanguage = this.language;
            this.language = language;
            return previousLanguage;
        }

        @Override
        public void setLanguageValidator(Language language) {
            // 👉 The Update validator performs validation but cannot mutate the Workflow state.
            if (!greetings.containsKey(language)) {
                throw new IllegalArgumentException("Unsupported language: " + language);
            }
        }
    }
}
```

- The Update annotation accepts arguments (`name`, and `unfinished_policy`) as described in the API reference docs for [`@UpdateMethod`](https://www.javadoc.io/doc/io.temporal/temporal-sdk/latest/io/temporal/workflow/UpdateMethod.html).

- About validators:
  - Use validators to reject an Update before it is written to History.
    Validators are always optional.
    If you don't need to reject Updates, you can skip them.
  - Define an Update validator with the `@UpdateValidatorMethod` annotation.
    Use the `updateName` argument when declaring the validator to connect it to its Update.
    The validator must return `void` and accept the same argument types as the handler.

- Accepting and rejecting Updates with validators:
  - To reject an Update, throw an exception of any type in the validator.
  - Without a validator, Updates are always accepted.
- Validators and Event History:
  - The `WorkflowExecutionUpdateAccepted` event is written into the History whether the acceptance was automatic or programmatic.
  - When a Validator throws an error, the Update is rejected, the Update is not run, and `WorkflowExecutionUpdateAccepted` _won't_ be added to the Event History.
    The caller receives an "Update failed" error.

- Use [`getCurrentUpdateInfo`](https://www.javadoc.io/doc/io.temporal/temporal-sdk/latest/io/temporal/internal/sync/WorkflowInternal.html#getCurrentUpdateInfo()) to obtain information about the current Update. This includes the Update ID, which can be useful for deduplication when using Continue-As-New: see [Ensuring your messages are processed exactly once](https://docs.temporal.io/encyclopedia/workflow-message-passing#exactly-once-message-processing).

- Signal (and Update) handlers can be blocking, letting them use Activities, Child Workflows, durable [`Workflow.sleep`](https://www.javadoc.io/doc/io.temporal/temporal-sdk/latest/io/temporal/workflow/Workflow.html#sleep(java.time.Duration)) Timers, [`Workflow.await`](https://www.javadoc.io/doc/io.temporal/temporal-sdk/latest/io/temporal/workflow/Workflow.html#await(java.time.Duration,java.util.function.Supplier)) conditions, and more.
  See [Blocking handlers](#blocking-handlers) and [Workflow message passing](/encyclopedia/workflow-message-passing) for safe usage guidelines.

## Send messages {#send-messages}

To send Queries, Signals, or Updates you call methods on a `WorkflowInterface`, often called the "WorkflowStub."

Use [newWorkflowStub](https://javadoc.io/doc/io.temporal/temporal-sdk/latest/io/temporal/client/WorkflowClient.html#newWorkflowStub(java.lang.Class,io.temporal.client.WorkflowOptions)) to obtain the WorkflowStub.

For example:

```java
WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs();

WorkflowClient client = WorkflowClient.newInstance(service);

WorkflowOptions workflowOptions =
    WorkflowOptions.newBuilder().setTaskQueue(TASK_QUEUE).setWorkflowId(WORKFLOW_ID).build();

// Create the workflow client stub. It is used to start the workflow execution.
GreetingWorkflow workflow = client.newWorkflowStub(GreetingWorkflow.class, workflowOptions);

// Start workflow asynchronously and call its getGreeting workflow method
WorkflowClient.start(workflow::getGreetings);
```

To check the argument types required when sending messages -- and the return type for Queries and Updates -- refer to the corresponding handler method in the Workflow Definition.

:::warning Using Continue-as-New and Updates

- Temporal _does not_ support Continue-as-New functionality within Update handlers.
- Complete all handlers _before_ using Continue-as-New.
- Use Continue-as-New from your main Workflow Definition method, just as you would complete or fail a Workflow Execution.

:::

### Send a Query {#send-query}

Call a Query method defined within a Workflow from a `WorkflowStub` created in Client code to send a Query to a Workflow Execution:

```java
List<Language> languages = workflow.getLanguages(new GetLanguagesInput(false));
System.out.println("Supported languages: " + languages);
```

- Sending a Query doesn’t add events to a Workflow's Event History.

- You can send Queries to closed Workflow Executions within a Namespace's Workflow retention period.
  This includes Workflows that have completed, failed, or timed out.
  Querying terminated Workflows is not safe and, therefore, not supported.

- A Worker must be online and polling the Task Queue to process a Query.

### Send a Signal {#send-signal}

You can send a Signal to a Workflow Execution from a Temporal Client or from another Workflow Execution.
However, you can only send Signals to Workflow Executions that haven’t closed.

#### Send a Signal from a Client {#send-signal-from-client}

To send a Signal from Client code, call a Signal method on the WorkflowStub:

```java
workflow.approve(new ApproveInput("Me"));
```

- The call returns when the server accepts the Signal; it does _not_ wait for the Signal to be delivered to the Workflow Execution.

- The [WorkflowExecutionSignaled](/references/events#workflowexecutionsignaled) Event appears in the Workflow's Event History.

#### Send a Signal from a Workflow {#send-signal-from-workflow}

A Workflow can send a Signal to another Workflow, known as an _External Signal_.
Use [`Workflow.newExternalWorkflowStub`](https://javadoc.io/doc/io.temporal/temporal-sdk/latest/io/temporal/workflow/Workflow.html#newExternalWorkflowStub(java.lang.Class,io.temporal.api.common.v1.WorkflowExecution)) in your _current_ Workflow to create an `ExternalWorkflowStub` for the other Workflow.
Call Signal methods on the external stub to Signal the other Workflow:

```java
OtherWorkflow other = Workflow.newExternalWorkflowStub(OtherWorkflow.class, otherWorkflowID);
other.mySignalMethod();
```

When an External Signal is sent:

- A [SignalExternalWorkflowExecutionInitiated](/references/events#signalexternalworkflowexecutioninitiated) Event appears in the sender's Event History.
- A [WorkflowExecutionSignaled](/references/events#workflowexecutionsignaled) Event appears in the recipient's Event History.

#### Signal-With-Start {#signal-with-start}

Signal-With-Start allows a Client to send a Signal to a Workflow Execution, starting the Execution if it is not already running.
If there's a Workflow running with the given Workflow Id, it will be signaled.
If there isn't, a new Workflow will be started and immediately signaled.
To use Signal-With-Start, call `signalWithStart` and pass the name of your Signal with its arguments:

```java
public static void signalWithStart() {
    // WorkflowStub is a client-side stub to a single Workflow instance
    WorkflowStub untypedWorkflowStub = client.newUntypedWorkflowStub("GreetingWorkflow",
    WorkflowOptions.newBuilder()
            .setWorkflowId(workflowId)
            .setTaskQueue(taskQueue)
            .build());

    untypedWorkflowStub.signalWithStart("setCustomer", new Object[] {customer2}, new Object[] {customer1});

    String greeting = untypedWorkflowStub.getResult(String.class);
}
```

Here's the `WorkflowInterface` for the previous example.
When using Signal-With-Start, the Signal handler (`setCustomer`) will be executed before the Workflow method (`greet`).

```java
@WorkflowInterface
public interface GreetingWorkflow {
    @WorkflowMethod
    String greet(Customer customer);

    @SignalMethod
    void setCustomer(Customer customer);

    @QueryMethod
    Customer getCustomer();
}
```

### Send an Update {#send-update-from-client}

An Update is a synchronous, blocking call that can change Workflow state, control its flow, and return a result.

A Client sending an Update must wait until the Server delivers the Update to a Worker.
Workers must be available and responsive.
If you need a response as soon as the Server receives the request, use a Signal instead.
Also note that you can't send Updates to other Workflow Executions or perform an Update equivalent of Signal-With-Start.

- `WorkflowExecutionUpdateAccepted` is added to the Event History when the Worker confirms that the Update passed validation.
- `WorkflowExecutionUpdateCompleted` is added to the Event History when the Worker confirms that the Update has finished.

To send an Update to a Workflow Execution, you can:

- Call the Update method on a WorkflowStub in Client code and wait for the Update to complete.
  This code fetches an Update result:

  ```java
  Language previousLanguage = workflow.setLanguage(Language.CHINESE);
  ```

- Send [`startUpdate`](https://javadoc.io/doc/io.temporal/temporal-sdk/latest/io/temporal/client/WorkflowStub.html#startUpdate(io.temporal.client.UpdateOptions,java.lang.Object...)) to receive an [`WorkflowUpdateHandle`](https://javadoc.io/doc/io.temporal/temporal-sdk/latest/io/temporal/client/WorkflowUpdateHandle.html) as soon as the Update is accepted or rejected.

  - Use this `WorkflowUpdateHandle` later to fetch your results.
  - Blocking Update handlers normally perform long-running asynchronous operations.
  - `startUpdate` only waits until the Worker has accepted or rejected the Update, not until all asynchronous operations are complete.

  For example:

  ```java
  WorkflowUpdateHandle<Language> handle =
      WorkflowStub.fromTyped(workflow)
          .startUpdate(
              "setLanguage", WorkflowUpdateStage.ACCEPTED, Language.class, Language.ENGLISH);
  previousLanguage = handle.getResultAsync().get();
  ```

  For more details, see the "Blocking handlers" section.

To obtain an Update handle, you can:

- Use [`startUpdate`](https://javadoc.io/doc/io.temporal/temporal-sdk/latest/io/temporal/client/WorkflowStub.html#startUpdate(io.temporal.client.UpdateOptions,java.lang.Object...)) to start an Update and return the handle, as shown in the preceding example.
- Use [`getUpdateHandle`](https://javadoc.io/doc/io.temporal/temporal-sdk/latest/io/temporal/client/WorkflowStub.html#getUpdateHandle(java.lang.String,java.lang.Class)) to fetch a handle for an in-progress Update using the Update ID and Workflow ID.

You can use the `WorkflowUpdateHandle` to obtain information about the update:

- `getExecution()`: Returns the Workflow Execution that this Update was sent to.
- `getId()`: Returns the Update's unique ID, which can be useful for deduplication when using Continue-As-New: see [Ensuring your messages are processed exactly once](/encyclopedia/workflow-message-passing#exactly-once-message-processing).
- `getResultAsync()`: Returns a `CompletableFuture` which can be used to wait for the Update to complete.

:::info NON-TYPE SAFE API CALLS

In real-world development, sometimes you may be unable to import Workflow Definition method signatures.
When you don't have access to the Workflow Definition or it isn't written in Java, you can use these non-type safe APIs to obtain an untyped WorkflowStub:

- [`WorkflowClient.newUntypedWorkflowStub`](https://javadoc.io/doc/io.temporal/temporal-sdk/latest/io/temporal/client/WorkflowClient.html#newUntypedWorkflowStub(java.lang.String,io.temporal.client.WorkflowOptions))
- [`Workflow.newUntypedExternalWorkflowStub`](https://javadoc.io/doc/io.temporal/temporal-sdk/latest/io/temporal/workflow/Workflow.html#newUntypedExternalWorkflowStub(java.lang.String)).

Pass method names instead of method objects to:

- [`WorkflowStub.query`](https://javadoc.io/doc/io.temporal/temporal-sdk/latest/io/temporal/client/WorkflowStub.html#query(java.lang.String,java.lang.Class,java.lang.Object...))
- [`WorkflowStub.signal`](https://javadoc.io/doc/io.temporal/temporal-sdk/latest/io/temporal/client/WorkflowStub.html#signal(java.lang.String,java.lang.Object...))
- [`WorkflowStub.update`](https://javadoc.io/doc/io.temporal/temporal-sdk/latest/io/temporal/client/WorkflowStub.html#update(java.lang.String,java.lang.Class,java.lang.Object...))
- [`WorkflowStub.startUpdate`](https://javadoc.io/doc/io.temporal/temporal-sdk/latest/io/temporal/client/WorkflowStub.html#startUpdate(io.temporal.client.UpdateOptions,java.lang.Object...))

:::

## Message handler patterns {#message-handler-patterns}

This section covers common write operations, such as Signal and Update handlers.
It doesn't apply to pure read operations, like Queries or Update Validators.

:::tip

For additional information, see [Inject work into the main Workflow](/encyclopedia/workflow-message-passing#injecting-work-into-main-workflow), and [Ensuring your messages are processed exactly once](/encyclopedia/workflow-message-passing#exactly-once-message-processing).

:::

### Do blocking operations in handlers {#blocking-handlers}

Signal and Update handlers can block.
This allows you to use [`Workflow.await`](https://www.javadoc.io/doc/io.temporal/temporal-sdk/latest/io/temporal/workflow/Workflow.html#await(java.time.Duration,java.util.function.Supplier)), Activities, Child Workflows, [`Workflow.sleep`](https://www.javadoc.io/doc/io.temporal/temporal-sdk/latest/io/temporal/workflow/Workflow.html#sleep(java.time.Duration)) Timers, etc.
This expands the possibilities for what can be done by a handler but it also means that handler executions and your main Workflow method are all running concurrently, with switching occurring between them at await calls.

It's essential to understand the things that could go wrong in order to use blocking handlers safely.
See [Workflow message passing](/encyclopedia/workflow-message-passing) for guidance on safe usage of blocking Signal and Update handlers, and the [Controlling handler concurrency](#control-handler-concurrency) and [Waiting for message handlers to finish](#wait-for-message-handlers) sections below.

The following code modifies the Update handler from earlier on in this page.
The Update handler now makes a blocking call to execute an Activity:

```java
public static class GreetingWorkflowImpl implements GreetingWorkflow {
    ...
    @Override
    public Language setLanguage(Language language) {
        if (!greetings.containsKey(language)) {
            String greeting = activity.greetingService(language);
            if (greeting == null) {
                // 👉 An update validator cannot be blocking, so cannot be used to check that the remote
                // greetingService supports the requested language. Throwing an ApplicationFailure
                // will fail the Update, but the WorkflowExecutionUpdateAccepted event will still be
                // added to history.
                throw ApplicationFailure.newFailure("Greeting service does not support: " + language, "GreetingFailure")
            }
            greetings.put(language, greeting);
        }
        Language previousLanguage = this.language;
        this.language = language;
        return previousLanguage;
    }
}
```

Although a Signal handler can also make blocking calls like this, using an Update handler allows the Client to receive a result or error once the Activity completes.
This lets your Client track the progress of asynchronous work performed by the Update's Activities, Child Workflows, etc.

### Add blocking wait conditions {#block-with-wait}

Sometimes, blocking Signal or Update handlers need to meet certain conditions before they should continue.
You can use [`Workflow.await`](https://www.javadoc.io/doc/io.temporal/temporal-sdk/latest/io/temporal/workflow/Workflow.html#await(java.time.Duration,java.util.function.Supplier)) to prevent the code from proceeding until a condition is true.
You specify the condition by passing a function that returns `true` or `false`.
This is an important feature that helps you control your handler logic.

Here are two important use cases for `Workflow.await`:

- Waiting in a handler until it is appropriate to continue.
- Waiting in the main Workflow until all active handlers have finished.

#### Wait for conditions in handlers {#wait-in-handlers}

It's common to use `Workflow.await` in a handler.
For example, suppose your Workflow class has a `updateReadyToExecute` method that indicates whether your Update handler should be allowed to start executing.
You can use `workflow.wait_condition` in the handler to make the handler pause until the condition is met:

```java
@Override
public String setLanguage(UpdateInput input) {
    Workflow.await(() -> this.updateReadyToExecute(input));
    ...
}
```

Remember: handlers can execute before the main Workflow method starts.

You can also use `Workflow.await` anywhere else in the handler to wait for a specific condition to become true.
This allows you to write handlers that pause at multiple points, each time waiting for a required condition to become true.

#### Ensure your handlers finish before the Workflow completes {#wait-for-message-handlers}

`Workflow.await` can ensure your handler completes before a Workflow finishes.
When your Workflow uses blocking Signal or Update handlers, your main Workflow method can return or Continue-as-New while a handler is still waiting on an async task, such as an Activity.
The Workflow completing may interrupt the handler before it finishes crucial work and cause Client errors when trying to retrieve Update results.
Use `Workflow.await` to wait for [`Workflow.isEveryHandlerFinished`](https://javadoc.io/doc/io.temporal/temporal-sdk/latest/io/temporal/workflow/Workflow.html#isEveryHandlerFinished()) to return `true` to address this problem and allow your Workflow to end smoothly:

```java
public class MyWorkflowImpl implements MyWorkflow {
    ...
    @Override
    public String run() {
        ...
        Workflow.await(() -> Workflow.isEveryHandlerFinished());
        return "workflow-result";
    }
}
```

By default, your Worker will log a warning when you allow a Workflow Execution to finish with unfinished handler executions.
You can silence these warnings on a per-handler basis by passing the `unfinishedPolicy` argument to the [`@SignalMethod`](https://www.javadoc.io/doc/io.temporal/temporal-sdk/latest/io/temporal/workflow/SignalMethod.html) / [`@UpdateMethod`](https://www.javadoc.io/doc/io.temporal/temporal-sdk/latest/io/temporal/workflow/UpdateMethod.html) annotation:

```java
@WorkflowInterface
public interface MyWorkflow {
    ...
    @UpdateMethod(unfinishedPolicy = HandlerUnfinishedPolicy.ABANDON)
    void myUpdate();
}
```

See [Finishing handlers before the Workflow completes](/encyclopedia/workflow-message-passing#finishing-message-handlers) for more information.

### Use `@WorkflowInit` to operate on Workflow input before any handler executes

Normally, your Workflows constructor won't have any parameters.
However, if you use the `@WorkflowInit` annotation on your constructor, you can give it the same [Workflow parameters](/develop/java/core-application#workflow-parameters) as your `@WorkflowMethod`.
The SDK will then ensure that your constructor receives the Workflow input arguments that the [Client sent](/develop/python/temporal-clients#start-workflow-execution).
The Workflow input arguments are also passed to your `@WorkflowMethod` method -- that always happens, whether or not you use the `@WorkflowInit` annotation.
This is useful if you have message handlers that need access to Workflow input: see [Initializing the Workflow first](/encyclopedia/workflow-message-passing#workflow-initializers).

Here's an example.
Notice that the constructor and `getGreeting` must have the same parameters:

```java
public class GreetingExample {
    @WorkflowInterface
    public interface GreetingWorkflow {
        @WorkflowMethod
        String getGreeting(String input);

        @UpdateMethod
        boolean checkTitleValidity();
    }

    public static class GreetingWorkflowImpl implements GreetingWorkflow {
        private final String nameWithTitle;
        private final String titleHasBeenChecked;
        ...
        // Note the annotation is on a public constructor
        @WorkflowInit
        public GreetingWorkflowImpl(String input) {
          this.nameWithTitle = "Sir " + input;
          this.titleHasBeenChecked = false;
        }

        @Override
        public String getGreeting(String input) {
          Workflow.await(() -> titleHasBeenChecked)
          return "Hello " + nameWithTitle;
        }

        @Override
        public boolean checkTitleValidity() {
          // 👉 The handler is now guaranteed to see the workflow input
          // after it has been processed by the constructor.
          boolean isValid = activity.checkTitleValidity(nameWithTitle);
          titleHasBeenChecked = true;
          return isValid;
        }
    }
}
```

### Use locks to prevent concurrent handler execution {#control-handler-concurrency}

Concurrent processes can interact in unpredictable ways.
Incorrectly written [concurrent message-passing](/encyclopedia/workflow-message-passing#message-handler-concurrency) code may not work correctly when multiple handler instances run simultaneously.
Here's an example of a pathological case:

```java
public class DataWorkflowImpl implements DataWorkflow {
    ...
    @Override
    public void badSignalHandler() {
        Data data = activity.fetchData();
        this.x = data.x;
        // 🐛🐛 Bug!! If multiple instances of this method are executing concurrently, then
        // there may be times when the Workflow has self.x from one Activity execution and self.y from another.
        Workflow.sleep(Duration.ofSeconds(1));
        this.y = data.y;
    }
}
```

Coordinating access with `WorkflowLock` corrects this code.
Locking makes sure that only one handler instance can execute a specific section of code at any given time:

```java
public class DataWorkflowImpl implements DataWorkflow {
    WorkflowLock lock = Workflow.newWorkflowLock();
    ...
    @Override
    public void safeSignalHandler() {
        try {
            lock.lock();
            Data data = activity.fetchData();
            this.x = data.x;
            // ✅ OK: the scheduler may switch now to a different handler execution,
            // or to the main workflow method, but no other execution of this handler
            // can run until this execution finishes.
            Workflow.sleep(Duration.ofSeconds(1));
            this.y = data.y;
        } finally {
            lock.unlock()
        }
    }
}
```

## Message handler troubleshooting {#message-handler-troubleshooting}

When sending a Signal, Update, or Query to a Workflow, your Client might encounter the following errors:

- **The Client can't contact the server**:
  You'll receive a [`WorkflowServiceException`](https://javadoc.io/doc/io.temporal/temporal-sdk/latest/io/temporal/client/WorkflowServiceException.html) on which the `cause` is a [`StatusRuntimeException`](https://grpc.github.io/grpc-java/javadoc/io/grpc/StatusRuntimeException.html) and `status` of `UNAVAILABLE` (after some retries).

- **The Workflow does not exist**:
  You'll receive a [`WorkflowNotFoundException`](https://javadoc.io/doc/io.temporal/temporal-sdk/latest/io/temporal/client/WorkflowNotFoundException.html).

See [Exceptions in message handlers](/encyclopedia/workflow-message-passing#exceptions) for a non–Java-specific discussion of this topic.

### Problems when sending a Signal {#signal-problems}

When using Signal, the above `WorkflowException`s are the only types of exception that will result from the request.

In contrast, for Queries and Updates, the client waits for a response from the Worker.
If an issue occurs during the handler execution by the Worker, the Client may receive an exception.

### Problems when sending an Update {#update-problems}

When working with Updates, you may encounter these errors:

- **No Workflow Workers are polling the Task Queue**:
  Your request will be retried by the SDK Client indefinitely.
  You can impose a timeout with `CompletableFuture.get()` method with a timeout parameter.
  This throws a `java.util.concurrent.TimeoutException` exception when it expires.

- **Update failed**: You'll receive a `WorkflowUpdateException` exception.
  There are two ways this can happen:

  - The Update was rejected by an Update validator defined in the Workflow alongside the Update handler.

  - The Update failed after having been accepted.

  Update failures are like [Workflow failures](/references/failures).
  Issues that cause a Workflow failure in the main method also cause Update failures in the Update handler.
  These might include:

      - A failed Child Workflow
      - A failed Activity (if the Activity retries have been set to a finite number)
      - The Workflow author throwing `ApplicationFailure`
      - Any error listed in [getFailWorkflowExceptionTypes](https://javadoc.io/doc/io.temporal/temporal-sdk/latest/io/temporal/worker/WorkflowImplementationOptions.html#getFailWorkflowExceptionTypes()) (empty by default)

- **The handler caused the Workflow Task to fail**:
  A [Workflow Task Failure](/references/failures) causes the server to retry Workflow Tasks indefinitely. What happens to your Update request depends on its stage:
  - If the request hasn't been accepted by the server, you receive a `FAILED_PRECONDITION` [`WorkflowServiceException`](https://javadoc.io/doc/io.temporal/temporal-sdk/latest/io/temporal/client/WorkflowServiceException.html) exception.
  - If the request has been accepted, it is durable.
    Once the Workflow is healthy again after a code deploy, use an `WorkflowUpdateHandle`](https://javadoc.io/doc/io.temporal/temporal-sdk/latest/io/temporal/client/WorkflowUpdateHandle.html) to fetch the Update result.

- **The Workflow finished while the Update handler execution was in progress**:
  You'll receive a [`WorkflowServiceException`](https://javadoc.io/doc/io.temporal/temporal-sdk/latest/io/temporal/client/WorkflowServiceException.html) "workflow execution already completed"`.

  This will happen if the Workflow finished while the Update handler execution was in progress, for example because

  - The Workflow was canceled or failed.

  - The Workflow completed normally or continued-as-new and the Workflow author did not [wait for handlers to be finished](/encyclopedia/workflow-message-passing#finishing-message-handlers).

### Problems when sending a Query {#query-problems}

When working with Queries, you may encounter these errors:

- **There is no Workflow Worker polling the Task Queue**:
  You'll receive a [`WorkflowServiceException`](https://javadoc.io/doc/io.temporal/temporal-sdk/latest/io/temporal/client/WorkflowServiceException.html) on which the `cause` is a [`StatusRuntimeException`](https://grpc.github.io/grpc-java/javadoc/io/grpc/StatusRuntimeException.html) with a `status` of `FAILED_PRECONDITION`.

- **Query failed**:
  You'll receive a [`WorkflowQueryException`](https://javadoc.io/doc/io.temporal/temporal-sdk/latest/io/temporal/client/WorkflowQueryException.html) exception if something goes wrong during a Query.
  Any exception in a Query handler will trigger this error.
  This differs from Signal and Update requests, where exceptions can lead to Workflow Task Failure instead.

- **The handler caused the Workflow Task to fail.**
  This would happen, for example, if the Query handler blocks the thread for too long without yielding.

## Dynamic components {#dynamic-handler}

A dynamic Workflow, Activity, Signal, Update, or Query is a kind of unnamed item.
Normally, these items are registered by name with the Worker and invoked at runtime.
When an unregistered or unrecognized Workflow, Activity, or message request arrives with a recognized method signature, the Worker can use a pre-registered dynamic stand-in.

For example, you might send a request to start a Workflow named "MyUnknownWorkflow".
After receiving a Workflow Task, the Worker may find that there's no registered Workflow Definitions of that type.
It then checks to see if there's a registered dynamic Workflow.
If the dynamic Workflow signature matches the incoming Workflow signature, the Worker invokes that just as it would invoke a non-dynamic statically named version.

By registering dynamic versions of your Temporal components, the Worker can fall back to these alternate implementations for name mismatches.

:::caution

Use dynamic elements judiciously and as a fallback mechanism, not a primary design.
They can introduce long-term maintainability and debugging issues.
Reserve dynamic invocation use for cases where a name is not or can't be known at compile time.

:::

### Set a Dynamic Workflow {#set-a-dynamic-workflow}

Use [`DynamicWorkflow`](https://www.javadoc.io/doc/io.temporal/temporal-sdk/latest/io/temporal/workflow/DynamicWorkflow.html) to implement Workflow Types dynamically.
Register a Workflow implementation type that extends `DynamicWorkflow` to implement any Workflow Type that is not explicitly registered with the Worker.

The dynamic Workflow interface is implemented with the `execute` method. This method takes in `EncodedValues` that are inputs to the Workflow Execution.
These inputs can be specified by the Client when invoking the Workflow Execution.

```java
public class MyDynamicWorkflow implements DynamicWorkflow {
   @Override
    public Object execute(EncodedValues args) {
    }
}
```

### How to set a Dynamic Activity {#set-a-dynamic-activity}

To handle Activity types that do not have an explicitly registered handler, you can directly implement a dynamic Activity.

Use `DynamicActivity` to implement any number of Activity types dynamically.
When an Activity implementation that extends `DynamicActivity` is registered, it is called for any Activity type invocation that doesn't have an explicitly registered handler.

The dynamic Activity interface is implemented with the `execute` method, as shown in the following example.

```java
// Dynamic Activity implementation
 public static class DynamicGreetingActivityImpl implements DynamicActivity {
   @Override
   public Object execute(EncodedValues args) {
     String activityType = Activity.getExecutionContext().getInfo().getActivityType();
     return activityType
         + ": "
         + args.get(0, String.class)
         + " "
         + args.get(1, String.class)
         + " from: "
         + args.get(2, String.class);
   }
 }
```

Use `Activity.getExecutionContext()` to get information about the Activity type that should be implemented dynamically.

### How to set a Dynamic Signal {#set-a-dynamic-signal}

You can also implement Signal handlers dynamically. This is useful for library-level code and implementation of DSLs.

Use `Workflow.registerListener(Object)` to register an implementation of the `DynamicSignalListener` in the Workflow implementation code.

```java
Workflow.registerListener(
  (DynamicSignalHandler)
      (signalName, encodedArgs) -> name = encodedArgs.get(0, String.class));
```

When registered, any Signals sent to the Workflow without a defined handler will be delivered to the `DynamicSignalHandler`.
Note that you can only register one `Workflow.registerListener(Object)` per Workflow Execution.
`DynamicSignalHandler` can be implemented in both regular and dynamic Workflow implementations.

### How to set a Dynamic Query {#set-a-dynamic-query}

You can also implement Query handlers dynamically. This is useful for library-level code and implementation of DSLs.

Use `Workflow.registerListener(Object)` to register an implementation of the `DynamicQueryListener` in the Workflow implementation code.

```java
Workflow.registerListener(
  (DynamicQueryHandler)
      (queryName, encodedArgs) -> name = encodedArgs.get(0, String.class));
```

When registered, any Queries sent to the Workflow without a defined handler will be delivered to the `DynamicQueryHandler`.
Note that you can only register one `Workflow.registerListener(Object)` per Workflow Execution.
`DynamicQueryHandler` can be implemented in both regular and dynamic Workflow implementations.

### How to set a Dynamic Update {#set-a-dynamic-update}

You can also implement Update handlers dynamically.
This is useful for library-level code and implementation of DSLs.

```java
Workflow.registerListener(
  (DynamicUpdateHandler)
      (updateName, encodedArgs) -> encodedArgs.get(0, String.class));
```

When registered, any Updates sent to the Workflow without a defined handler will be delivered to the `DynamicUpdateHandler`.
You can only register one `Workflow.registerListener(Object)` per Workflow Execution.
`DynamicUpdateHandler` can be implemented in both regular and dynamic Workflow implementations.
